//
// Created by tcj on 2022/7/16.
//

#include "HTTPrequest.h"

namespace tcj{
    const std::unordered_set<std::string> HTTPrequest::DEFAULT_HTML_{
            "/index", "/welcome", "/video", "/picture"};

    HTTPrequest::HTTPrequest() {
        init();
    }

    void HTTPrequest::init() {
        method_ = path_ = version_ = body_ = "";
        state_ = REQUEST_LINE;
        header_.clear();
        post_.clear();
    }

    bool HTTPrequest::isKeepAlive() const {
        if(header_.count("Connection") == 1){
            return header_.find("Connection")->second == "keep-alive" && version_ == "1.1";
        }
        return false;
    }

    bool HTTPrequest::parse(Buffer &buffer) {
        const char CRLF[] = "\r\n";
        if(buffer.readableBytes() <=0) return false;
        cout<<"parse start "<<endl;
        while(buffer.readableBytes() && state_ != FINISH){
            // search找到第二个在第一个中出现的位置
            const char* lineEnd = std::search(buffer.curReadPtr(), buffer.curWritePtrconst(), CRLF, CRLF + 2);
            std::string line(buffer.curReadPtr(), lineEnd);
            cout<<"解析的数据:  "<<line<<endl;
            switch (state_) {
                case REQUEST_LINE:
                    if(!parseRequestLine_(line)) return false;
                    parsePath_();
                    break;
                case HEADRS:
                    parseRequestHeader_(line);
                    if(buffer.readableBytes() <= 2) {
                        std::cout<<buffer.readableBytes()<<std::endl;
                        state_ = FINISH;
                    }
                    break;
                case BODY:
                    parseDataBody_(line);
                    break;
                default:
                    break;
            }
            if(lineEnd == buffer.curWritePtr()) break;
            buffer.updateReadPtrUntilEnd(lineEnd+1);
        }
        cout<<"parse end"<<endl;
        return true;
    }

    // 找到网页所在地
    void HTTPrequest::parsePath_() {
        if (path_ == "/"){
            path_ = "/index.html";
        }else{
            for(auto &item : DEFAULT_HTML_){
                if(item == path_){
                    path_ += ".html";
                    break;
                }
            }
        }
    }

    bool HTTPrequest::parseRequestLine_(const std::string &line) {
        std::regex patten("^([^ ]*) ([^ ]*) HTTP/([^ ]*)$");
        std::smatch subMatch;
        // regex_match:在整个字符串中匹配到符合整个表达式的整个字符串时返回true，也就是匹配的是整个字符串
        // 使用正则表达式进行全文匹配，得到请求行，并对请求头数据进行存储
        if(regex_match(line,subMatch,patten)) {
            method_ = subMatch[1];
            path_ = subMatch[2];
            version_ = subMatch[3];
            state_ = HEADRS;
            return true;
        }
        return false;
    }

    void HTTPrequest::parseRequestHeader_(const std::string &line) {
        std::regex patten("^([^:]*): ?(.*)$");
        std::smatch subMatch;
        if(regex_match(line,subMatch,patten)){
            header_[subMatch[1]] = subMatch[2];
        }else{
            state_ = BODY;
        }
    }

    void HTTPrequest::parseDataBody_(const std::string &line) {
        body_ = line;
        parsePost_();
        state_ = FINISH;
    }

    int HTTPrequest::convertHex(char ch) {
        if( ch >= 'A' && ch<='F') return ch - 'A' +10;
        if( ch >= 'a' && ch<='f') return ch - 'a' +10;
        return ch;
    }

//    处理数据体的时候，如果格式是post，还需要进行解析post报文
    void HTTPrequest::parsePost_() {
        if(method_ == "post" && header_["Content-Type"] == "application/x-www-form-urlencoded"){
            if (body_.size() == 0) return;
            std::string  key , value;
            int num =0;
            int n=body_.size();
            int i=0,j=0;
            for (; i < n; ++i) {
                char ch = body_[i];
                switch (ch) {
                    case '=':
                        key = body_.substr(j,i-j);
                        j = i+1;
                        break;
                    case '+':
                        body_[i] = ' ';
                        break;
                    case '%':
                        num = convertHex(body_[i+1]) *16 + convertHex(body_[i+2]);
                        body_[i+2] = num % 10  + '0';
                        body_[i+1] = num / 10 + '0';
                        i +=2;
                        break;
                    case '&':
                        value = body_.substr(j,i-j);
                        j = i+1;
                        post_[key] = value;
                        break;
                    default:
                        break;
                }
            }
            assert(j <= i);
            if (post_.count(key) == 0 && j<=i){
                value = body_.substr(j,j-i);
                post_[key] =value;
            }
            cout<<"请求数据:"<<endl;
            for(auto & po:post_){
                cout<<po.first<<" : "<<po.second<<endl;
            }
        }
    }

    std::string &HTTPrequest::path() {
        return path_;
    }

    std::string HTTPrequest::path() const {
        return path_;
    }

    std::string HTTPrequest::method() const {
        return method_;
    }

    std::string HTTPrequest::version() const {
        return version_;
    }

    std::string HTTPrequest::getPost(const string& key) const {
        assert(key != "");
        if(post_.count(key)==1){
            return post_.find(key)->second;
        }
        return "";
    }

    std::string HTTPrequest::getPost(const char *key) const {
        assert(key != nullptr);
        if (post_.count(key) == 1){
            return post_.find(key)->second;
        }
        return "";
    }




}